package com.wctj.api.web.config;


import com.google.common.base.Strings;
import com.wctj.api.base.Result;
import com.wctj.api.base.enums.ApiCode;
import com.wctj.api.base.enums.ApiHeader;
import com.wctj.api.base.exception.CustomException;
import com.wctj.api.base.utils.ResponseEntityUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 *
 */
@ControllerAdvice
public class ErrorHandler extends ResponseEntityUtil {

    protected static final Logger log = LoggerFactory.getLogger(ErrorHandler.class);

    @Autowired
    protected HttpServletRequest httpRequest;

    @ExceptionHandler(value = {IllegalArgumentException.class})
    public ResponseEntity<Result> illegalArgumentException(IllegalArgumentException ex) {
        log.error("IllegalArgumentException|msg|{}", ex.getMessage(), ex);
        return renderError(ApiCode.INVALID_PARAMETER, ex.getMessage());
    }

    @ExceptionHandler(value = {HttpMessageNotReadableException.class})
    public ResponseEntity<Result> httpMessageNotReadableException(HttpMessageNotReadableException ex) {
        log.warn("httpMessageNotReadableException|msg|{}", ex.getMessage(), ex);
        return renderError(ApiCode.INVALID_PARAMETER_CHECK);
    }

    @ExceptionHandler(value = {HttpRequestMethodNotSupportedException.class})
    public ResponseEntity<Result> runtimeException(HttpRequestMethodNotSupportedException ex) {
        log.error("HttpRequestMethodNotSupportedException|msg|{}", ex.getMessage(), ex);
        return renderError(ApiCode.INTERNAL_SERVER_ERROR, ex.getMessage());
    }

    @ExceptionHandler(value = {CustomException.class})
    public ResponseEntity<Result> customException(CustomException ex) {
        log.error("CustomException|code|{}|msg|{}", ex.getApiCode(), ex.getMessage());
        return renderError(ex.getApiCode(), ex.getMessage());
    }

    @ExceptionHandler(value = {RuntimeException.class})
    public ResponseEntity<Result> runtimeException(RuntimeException ex) {
        log.error("RuntimeException|msg|{}", ex.getMessage(), ex);
        return renderError(ApiCode.SERVER_ERROR, ex.getMessage());
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ResponseEntity<Result> handleMethodArgumentNotValidException(MethodArgumentNotValidException me) {
        BindingResult bindingResult = me.getBindingResult();
        return handleInvalidParameter(bindingResult);
    }

    @ExceptionHandler({BindException.class})
    public ResponseEntity<Result> handleBindException(BindException be) {
        BindingResult bindingResult = be.getBindingResult();
        return handleInvalidParameter(bindingResult);
    }

    private ResponseEntity<Result> handleInvalidParameter(BindingResult bindingResult) {
        StringBuffer buffer = new StringBuffer("参数不合法");
        List<FieldError> errors = bindingResult.getFieldErrors();
        if (!errors.isEmpty()) {
            buffer.append(",");
            errors.stream().forEach((e) -> {
                buffer.append("字段【").append(e.getField()).append("】:").append(e.getDefaultMessage()).append(";");
            });
        }
        return renderError(ApiCode.INVALID_PARAMETER, buffer.toString());
    }


    @ExceptionHandler(value = {Exception.class})
    public ResponseEntity<Result> uncaughtException(Exception ex) {
        String sessionId = httpRequest.getHeader(ApiHeader.SESSION_ID.value());
        String requestId = httpRequest.getHeader(ApiHeader.REQUEST_ID.value());
        String timestamp = httpRequest.getHeader(ApiHeader.TIMESTAMP.value());

        Result result = new Result(ApiCode.INTERNAL_SERVER_ERROR);

        HttpHeaders headers = new HttpHeaders();
        headers.add(ApiHeader.SESSION_ID.name(), Strings.nullToEmpty(sessionId));
        headers.add(ApiHeader.REQUEST_ID.name(), Strings.nullToEmpty(requestId));
        headers.add(ApiHeader.TIMESTAMP.name(), Strings.nullToEmpty(timestamp));
        log.error("ErrorHandler", ex);
        return new ResponseEntity<>(result, headers, HttpStatus.INTERNAL_SERVER_ERROR);
    }


}
